﻿using System;
using System.Collections.Generic;
using System.Text;

namespace SGGWElevator
{
    /// <summary>
    /// Enum representing floors.
    /// Author: Paweł Iżycki
    /// </summary>
    public enum Floor { Undifined, MinusOne, Lobby, One, Two, Three };

    /// <summary>
    /// This class contains additional operations on floors.
    /// </summary>
    public static class ExtFloor
    {
        /// <summary>
        /// Sorted ascending array of floors.
        /// </summary>
        private static readonly Floor[] _floors = 
        {
            Floor.MinusOne,
            Floor.Lobby,
            Floor.One, 
            Floor.Two,
            Floor.Three
        };

        /// <summary>
        /// Collection of floors.
        /// </summary>
        public static IEnumerable<Floor> Floors
        {
            get { return _floors; }
        }

        /// <summary>
        /// Gets next floor.
        /// </summary>
        /// <returns>Following floor</returns>
        public static Floor GetNext(this Floor floor)
        {
            if (floor == Floor.Undifined)
                throw new UndifinedFloorException();

            for (int i = 0; i < _floors.Length - 1; i++)
            {
                if (_floors[i] == floor)
                    return _floors[i + 1];
            }

            // If there isn't any next floor, return the same floor.
            return floor;
        }


        /// <summary>
        /// Gets previous floor. 
        /// </summary>
        /// <returns>Previous floor</returns>
        public static Floor GetPrevious(this Floor floor)
        {
            if (floor == Floor.Undifined)
                throw new UndifinedFloorException();

            for (int i = _floors.Length - 1; i > 0; i--)
            {
                if (_floors[i] == floor)
                    return _floors[i - 1];
            }
            // If there isn't any previous floor, return the same floor.
            return floor;
        }

        /// <summary>
        /// Checks if the wanted floor is after the given floor.
        /// </summary>
        /// <param name="wantedFloor">Wanted floor</param>
        /// <param name="floor">Point of reference</param>
        /// <returns>True or false</returns>
        public static bool IsAfter(this Floor wantedFloor, Floor floor)
        {
            if (floor == Floor.Undifined || wantedFloor == Floor.Undifined)
                throw new UndifinedFloorException();

            if (floor == wantedFloor)
                return false;

            int givenFloorIndex = Array.IndexOf(_floors, floor);
            var searchedFloorList = new List<Floor>(_floors);
            searchedFloorList.RemoveRange(0, givenFloorIndex);
            return searchedFloorList.Exists(x => x == wantedFloor);
        }

        /// <summary>
        /// Checks if the wanted floor is before the given floor.
        /// </summary>
        /// <param name="wantedFloor">Wanted floor</param>
        /// <param name="floor">Point of reference</param>
        /// <returns>True or false</returns>
        public static bool IsBefore(this Floor wantedFloor, Floor floor)
        {
            if (floor == Floor.Undifined || wantedFloor == Floor.Undifined)
                throw new UndifinedFloorException();

            if (floor == wantedFloor)
                return false;

            int givenFloorIndex = Array.IndexOf(_floors, floor);
            var searchedFloorList = new List<Floor>(_floors);
            searchedFloorList.RemoveRange(givenFloorIndex, searchedFloorList.Count - givenFloorIndex);
            return searchedFloorList.Exists(x => x == wantedFloor);
        }
    }
    public class UndifinedFloorException : Exception
    {
        public UndifinedFloorException() : base("The floor is not defined.") { }
    }
}
